feat(storage,entity): path identity + speculation path→build mapping store#331
Open
behinddwalls wants to merge 1 commit into
Open
Conversation
This was referenced Jul 10, 2026
This was referenced Jul 10, 2026
…store
## Summary
### Why?
Integrating speculation needs the controllers to answer "which build belongs to this path" in both directions, without ever looking a row up by non-key attribute — the storage contract stays get/put-by-key so any KV backend can satisfy it. The build system mints its own build identifiers, and those stay the build store's primary key: the runner's ID is the natural name for the build row. What's missing is a durable link between a tree path and its build that exists independent of any in-flight message, plus a well-defined path identity to hang that link on.
### What?
`entity.SpeculationPathInfo` gains `ID` — an assigned, immutable path identity, unique within its tree, minted by the speculate controller when it creates the tree (so it exists before any build is triggered and survives crashes). `entity.SpeculationPathBuild` is the new mapping entity ({PathID, BuildID, BatchID, Version, CreatedAt}, named after its `speculation_path_build` table) with a `SpeculationPathBuildStore` (Create/Get keyed by PathID): the forward path→build lookup, written only by the build controller, at most one build per path with ErrAlreadyExists making the existing row the truth on races. BatchID makes the row self-describing without parsing PathID's format; Version follows the repo's optimistic-locking convention (write-once today, reserved for future conditional re-pointing flows). `entity.Build` keeps the runner-minted `ID` as its primary key and gains `SpeculationPathID` as a plain column — the reverse build→path lookup; the previously embedded `SpeculationPath` value is dropped as a redundant denormalized copy of what the tree already stores. `SpeculationPath.Equal` (order-sensitive Base + Head) provides structural path identity for decision matching. `entity.QueueID` with ToBytes/QueueIDFromBytes mirrors the BatchID payload pattern for queue-scoped stages.
MySQL gains the `speculation_path_build` table and the build table swaps `speculation_path`/`runner_id` for `speculation_path_id`; schema files are picked up automatically (the schema dir is globbed by both Bazel and the testutil ApplySchema helper).
## Test Plan
✅ `make gazelle && make fmt && make test` (74/74). ✅ `bazel test //test/integration/submitqueue/extension/storage/...` against real Docker MySQL: Build round-trip with runner-style ID + SpeculationPathID, SpeculationPathBuild Create/Get round-trip incl. BatchID and Version, duplicate Create → ErrAlreadyExists, missing Get → ErrNotFound. Unit tables cover SpeculationPath.Equal and entity serialization incl. the new fields.
f3c68e1 to
0426ccb
Compare
2551cf4 to
bbc4956
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Why?
Integrating speculation needs the controllers to answer "which build belongs to this path" in both directions, without ever looking a row up by non-key attribute — the storage contract stays get/put-by-key so any KV backend can satisfy it. The build system mints its own build identifiers, and those stay the build store's primary key: the runner's ID is the natural name for the build row. What's missing is a durable link between a tree path and its build that exists independent of any in-flight message, plus a well-defined path identity to hang that link on.
What?
entity.SpeculationPathInfogainsID— an assigned, immutable path identity, unique within its tree, minted by the speculate controller when it creates the tree (so it exists before any build is triggered and survives crashes).entity.SpeculationPathBuildis the new mapping entity ({PathID, BuildID, BatchID, Version, CreatedAt}, named after itsspeculation_path_buildtable) with aSpeculationPathBuildStore(Create/Get keyed by PathID): the forward path→build lookup, written only by the build controller, at most one build per path with ErrAlreadyExists making the existing row the truth on races. BatchID makes the row self-describing without parsing PathID's format; Version follows the repo's optimistic-locking convention (write-once today, reserved for future conditional re-pointing flows).entity.Buildkeeps the runner-mintedIDas its primary key and gainsSpeculationPathIDas a plain column — the reverse build→path lookup; the previously embeddedSpeculationPathvalue is dropped as a redundant denormalized copy of what the tree already stores.SpeculationPath.Equal(order-sensitive Base + Head) provides structural path identity for decision matching.entity.QueueIDwith ToBytes/QueueIDFromBytes mirrors the BatchID payload pattern for queue-scoped stages.MySQL gains the
speculation_path_buildtable and the build table swapsspeculation_path/runner_idforspeculation_path_id; schema files are picked up automatically (the schema dir is globbed by both Bazel and the testutil ApplySchema helper).Test Plan
✅
make gazelle && make fmt && make test(74/74). ✅bazel test //test/integration/submitqueue/extension/storage/...against real Docker MySQL: Build round-trip with runner-style ID + SpeculationPathID, SpeculationPathBuild Create/Get round-trip incl. BatchID and Version, duplicate Create → ErrAlreadyExists, missing Get → ErrNotFound. Unit tables cover SpeculationPath.Equal and entity serialization incl. the new fields.Issues
Stack